Setting up

library(httr)
library(rjson)
library(OpenStreetMap)
## Warning: package 'OpenStreetMap' was built under R version 4.0.3
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.0.3
library(scales)
library(dplyr)
library(purrr)
library(tidyverse)
library(sf)
library(htmltools)
library(htmlwidgets)
library(googlePolylines)
## Warning: package 'googlePolylines' was built under R version 4.0.3
library (rStrava) # devtools::install_github('fawda123/rStrava')

Set up the API

This was the tutorial I followed to get the Strava API set up. I followed steps one and two, then switched to this tutorial. Then in R, create the authentication token using your personal information from your API. Replace the app_name, app_client_id, and app_secret objects with the relevant info from your account.

app_name <- 'myappname' # chosen by user
app_client_id  <- 'myid' # an integer, assigned by Strava
app_secret <- 'xxxxxxxx' # an alphanumeric secret, assigned by Strava
# create the authentication token
stoken <- httr::config(token = strava_oauth(app_name, app_client_id, app_secret, app_scope="activity:read_all"))

Getting the data

Using the Strava API, I pulled all activities since June 1, 2019. This includes runs, bike rides, hikes, yoga, etc. This process relies on the rStrava package, which I navigated with the help of its developers at this link and this link

# get activities list
my_runs <- get_activity_list(stoken, id = NULL, before = NULL, after = as.Date("2019-06-01"), club = FALSE)

Compiling dataframe

I filtered all of my activities to show only runs. I also created a new dataframe with a subset of columns to make the data easier to work with.

my_runs_df <- compile_activities(my_runs) %>%
  filter (type == "Run", manual==FALSE)
desired_columns <- c('distance', 'average_speed', 'moving_time', 'start_date', 'start_date_local', 'map.summary_polyline', 'id', 'start_latitude', 'start_longitude', 'total_elevation_gain')

my_runs_df <- select(my_runs_df, match(desired_columns, names(my_runs_df)))

my_runs_df <- mutate(my_runs_df,
                  activity_no = seq(1,n(), 1),
                  moving_time = moving_time/60/60, 
                  date = gsub("T.*$", '', start_date) %>%
                    as.POSIXct(., format = '%Y-%m-%d'),
                  month = format(date, "%m"),
                  day = format(date, "%d"),
                  year = format(date, "%Y")) %>%
  mutate_at(., c('month', 'day'), as.numeric)

lons.range <- c(-71.25, -71.1)
lats.range <- c(42.33, 42.44)

view(my_runs_df)

Figuring out how to decode Google polylines

Strava gives you spatial data in an encoded polyline. You can do a lot with this if you’re willing to get an API key from Google but it will require credit card information. The workaround is to use the Google Polylines package in R to decode the data, which I learned about from here. I mapped one run as a test.

run_one <- decode(my_runs_df$map.summary_polyline[1])
run_one_df <- data.frame(run_one)

leaflet(run_one_df) %>% 
    addProviderTiles(providers$Stamen.TonerLite) %>% 
    addPolylines(lng = ~ lon, lat = ~ lat)

Decoding all of the polylines

Once I figured out how to work with the encoded polylines, I wrote a function that would decode each polyline in the dataframe called my_runs_df. Map.summary_polyline is the column where the spatial data is located.

run_list = purrr::map(my_runs_df$map.summary_polyline, function(x) decode(x))

Plot all the runs with a for loop

Full credit for this problem solving goes to my partner John Russell, resident Python wizard, and also this stack overflow

all_runs <- leaflet() %>% 
    addProviderTiles(providers$Stamen.TonerLite) %>%
    setView(lng=-71.122859,lat=42.397434,zoom=11) %>%
  addControl("Running Routes in Somerville and Beyond", position = "topright")

for(i in 1:length(run_list)){
  all_runs <- all_runs %>% addPolylines(data = data.frame(run_list[i]),
                                        lng = ~ lon,
                                        lat= ~ lat,
                                        #label=i,
                                        weight=0.6)

}

all_runs
saveWidget(all_runs, file = "allruns.html")

Looking at my routes in more detail

I manually selected seven routes that I would map in more detail. I assigned each of them a name and created labels that would show total distance and elevation gain.

fave_run_nums <- c(52, 185, 193, 81, 110,74, 210)
fave_run_names <- c("Full Minuteman", "Mystic Lakes Loop", "Fresh Pond Loop", "Tufts Track", "Home from the office", "Long Charles Loop", "Alewife Loop")

fave_runs <- leaflet() %>% 
    addProviderTiles(providers$Stamen.TonerLite) %>%
    setView(lng=-71.122859,lat=42.397434,zoom=11) %>%
addControl("My Favorite Routes", position = "topright")

for(i in 1:length(fave_run_nums)){
  describe <- paste(fave_run_names[i], "<br>", prettyNum(my_runs_df$distance[fave_run_nums[i]], digits = 3), " kilometers", "<br>",
prettyNum(my_runs_df$total_elevation_gain[fave_run_nums[i]], digits = 3), "meters elevation") %>%
  lapply(htmltools::HTML)

  fave_runs <- fave_runs %>% addPolylines(data = data.frame(run_list[fave_run_nums[i]]),
                                        lng = ~ lon,
                                        lat= ~ lat,
                                        popup=describe,
                                        weight=2,
                                        highlightOptions = highlightOptions(color = "orange", weight = 6))

}

fave_runs
saveWidget(fave_runs, file = "faveruns.html")

Combining the two maps

After Monday’s class, I wanted to see if I could add a layer that would allow me to toggle on/off my favorite routes.

combined_runs <- leaflet() %>% 
    addProviderTiles(providers$Stamen.TonerLite) %>%
    setView(lng=-71.122859,lat=42.397434,zoom=11) %>%
  addControl("Running Routes in Somerville and Beyond", position = "topright")

for(i in 1:length(run_list)){
  combined_runs <- combined_runs %>% addPolylines(data = data.frame(run_list[i]),
                                        lng = ~ lon,
                                        lat= ~ lat,
                                        #label=i,
                                        weight=0.6,
                                        color="blue")

} %>%
  
addLayersControl(overlayGroups = fave_run_nums, options = layersControlOptions(collapsed = FALSE))
  
  for(i in 1:length(fave_run_nums)){
  describe <- paste(fave_run_names[i], "<br>", prettyNum(my_runs_df$distance[fave_run_nums[i]], digits = 3), " kilometers", "<br>",
prettyNum(my_runs_df$total_elevation_gain[fave_run_nums[i]], digits = 3), "meters elevation") %>%
  lapply(htmltools::HTML)

  fave_runs <- fave_runs %>% addPolylines(data = data.frame(run_list[fave_run_nums[i]]),
                                        lng = ~ lon,
                                        lat= ~ lat,
                                        popup=describe,
                                        color="orange",
                                        weight=2,
                                        highlightOptions = highlightOptions(color = "red", weight = 6))

}

combined_runs